/*
  main.c: gtk driver for dcalc

    Contact info:
    bob.hepple@gmail.com
    http://bhepple.freeshell.org/dcalc/unix

    Copyright (C) 1999-2012 Bob Hepple

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; see the file COPYING.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.

 */

/* $Id: main.c,v 1.15 2006/12/31 09:06:53 bhepple Exp $ */

/* With glade 0.5.11 that every time the menubar is edited, one item
   in every radio group is turned on and interface.c gets a
   gtk_check_menu_item_set_active for that item. This results in
   seemingly harmless but distracting runtime errors. */

/* To build:
   cd .../dcalc/gtk
   aclocal
   autoconf
   autoheader
   automake
   configure
   (the above may happen automagically by typing 'make')
   cd src
   make
   make install
   whew
*/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <ctype.h>
#include <gnome.h>
#include <sys/param.h>

#include "interface.h"
#include "support.h"
#include "dcalc.h"
#include "callbacks.h"
#include "main.h"

/* naughty global exported to callbacks.c: */
GtkWidget *main_window;
GtkWidget *mem_dialog;
GtkWidget *eval_dialog;
GtkWidget *convert;
GtkWidget *registers = NULL;
GtkEntry  *entryX;
GtkButton *invert_button;

int mem_value;
int raw_mode = 0;
int is_resident = 0;
int insertedTextIsFromDcalc = 1;

dcalc_button *l_buttons, *r_buttons;
char calculatorFont[100];
char buttonFont[100];
char plusMinusFont[100];

dcalc_button sci_buttons[] = {
  { 0, 0, SIN, "SIN", "Sine of X (or INV)", "SIN(", "ASIN(" },
  { 0, 1, COS, "COS", "Cosine of X (or INV)", "COS(", "ACOS(" },
  { 0, 2, TAN, "TAN", "Tangent of X (or INV)", "TAN(", "ATAN(" },
  { 0, 3, HMS, "h.ms", "Convert X to Hours.MinsSecs (or INV)", "HMS(", "HOURS(" },
  { 0, 4, RTOP, "r->p", "Convert (X,Y) to polar coordinates (or INV)", "RTOP ", "PTOR " },
  { 0, 5, DTOR, "d->r", "Convert degrees to radians (or INV)", "DTOR(", "RTOD(" },
  { 0, 6, LOG10, "LOG", "Logarithm (base 10) (or INV)", "LOG10(", "ALOG10(" },
  { 0, 7, LOGE, "LN", "Natural logarithm (base e) (or INV)", "LOGe(", "ALOGe" },
  { 1, 0, SINH, "SINh", "Hyperbolic sine (or INV)", "SINH(", "ASINH(" },
  { 1, 1, COSH, "COSh", "Hyperbolic cosine (or INV)", "COSH(", "ACOSH(" },
  { 1, 2, TANH, "TANh", "Hyperbolic tangent (or INV)", "TANH(", "ATANH(" },
  { 1, 3, NOP, " ", " ", "", "" },
  { 1, 4, NOP, " ", " ", "", "" },
  { 1, 5, PI, "PI", "PI", "PI ", "" },
  { 1, 6, INT, "INT", "Integer part of X", "INT(", "" },
  { 1, 7, FRC, "FRC", "Fractional part of X", "FRC(", "" },
  { 2, 0, INV, "INV", "Invert functions", "", "" },
  { 2, 1, NOP, " ", " ", "", "" },
  { 2, 2, NOP, " ", " ", "", "" },
  { 2, 3, NOP, " ", " ", "", "" },
  { 2, 4, NOP, " ", " ", "", "" },
  { 2, 5, E, "e", "Base of natural logs", " e ", "" },
  { 2, 6, NOP, " ", " ", "", "" },
  { 2, 7, EVAL, "Eval", "Last algebraic expression", "", "" },
  { -1, -1, 0, " ", " ", "", "" }
};

dcalc_button fin_buttons[] = {
  { 0, 0, NFIN, "n", "Number of periods (or INV)", "", "" },
  { 0, 1, INTST, "i", "Interest rate in % per period (or INV)", "", "" },
  { 0, 2, PVAL, "PV", "Present value (or INV)", "", "" },
  { 0, 3, PMT, "PMT", "Payment (or INV)", "", "" },
  { 0, 4, FVAL, "FV", "Future value (or INV)", "", "" },
  { 0, 5, FCLR, "CLf", "Clear compound interest registers (5-9)", "", "" },
  { 0, 6, LOG10, "LOG", "Logarithm (base 10) (or INV)", "LOG(", " 10^" },
  { 0, 7, LOGE, "LN", "Natural logarithm (base e)", "LN(", " e^" },
  { 1, 0, TIMES12, "x12", "X times 12", "x12 ", "/12 " },
  { 1, 1, DIVIDE12, "/12", "X divided by 12", "/12 ", "x12 " },
  { 1, 2, BEGIN, "B/E", "Toggle Annuity at beginning of period", "", "" },
  { 1, 3, DYS, "DYS", "Days between dates", " DYS ", "" },
  { 1, 4, TDY, "TDY", "Today's date", " TDY ", "" },
  { 1, 5, PI, "PI", "PI", "PI ", "" },
  { 1, 6, INT, "INT", "Integer part of X", "INT(", "" },
  { 1, 7, FRC, "FRC", "Fractional part of X", "FRC(", "" },
  { 2, 0, INV, "INV", "Invert functions", "", "" },
  { 2, 1, NOP, " ", " ", "", "" },
  { 2, 2, NOP, " ", " ", "", "" },
  { 2, 3, NOP, " ", " ", "", "" },
  { 2, 4, NOP, " ", " ", "", "" },
  { 2, 5, E, "e", "Base of natural logs", " e ", "" },
  { 2, 6, NOP, " ", " ", "", "" },
  { 2, 7, EVAL, "Eval", "Last algebraic expression", "", "" },
  { -1, -1, 0, " ", " ", "", "" }
};
  
dcalc_button stat_buttons[] = {
  { 0, 0, SUM, "SUM+", "Add X to the accumulator (register 7)", "", "" },
  { 0, 1, MEAN, "m(X)", "Calculate the mean of X", "", "" },
  { 0, 2, MEANY, "m(Y)", "Calculate the mean of Y", "", "" },
  { 0, 3, S_DEV, "StdD", "Calculate the standard deviations", "", "" },
  { 0, 4, NSTAT, "N", "Number of samples", "", "" },
  { 0, 5, FACT, "x!", "X factorial", "!", "" },
  { 0, 6, LOG10, "LOG", "Logarithm (base 10)", "LOG(", " 10^" },
  { 0, 7, LOGE, "LN", "Natural logarithm (base e)", "LN(", " e^" },
  { 1, 0, SUMR, "SUM-", "subtract X from the accumulator (register 7)", "", "" },
  { 1, 1, PERM, "yPx", "x permutations of y", "yPx ", "" },
  { 1, 2, COMB, "yCx", "x combinations of y", "yCx ", "" },
  { 1, 3, LR, "LR", "Linear Regression", "LR", "" },
  { 1, 4, CALCY, "f(x)", "Calculate Y from X using linear regression results (Inv: calculate X from Y)", "Fx(", "" },
  { 1, 5, PI, "PI", "PI", "PI ", "" },
  { 1, 6, INT, "INT", "Integer part of X", "INT(", "" },
  { 1, 7, FRC, "FRC", "Fractional part of X", "FRC(", "" },
  { 2, 0, INV, "INV", "Invert functions", "", "" },
  { 2, 1, NOP, " ", " ", "", "" },
  { 2, 2, NOP, " ", " ", "", "" },
  { 2, 3, NOP, " ", " ", "", "" },
  { 2, 4, NOP, " ", " ", "", "" },
  { 2, 5, E, "e", "e", " e ", "" },
  { 2, 6, NOP, " ", " ", "", "" },
  { 2, 7, EVAL, "Eval", "Last algebraic expression", "", "" },
  { -1, -1, 0, " ", " ", "", "" }
};
  
dcalc_button prog_buttons[] = {
  { 0, 0, BIN, "BIN", "Binary mode", "", "" },
  { 0, 1, OCT, "OCT", "Octal mode", "", "" },
  { 0, 2, DEC, "DEC", "Decimal mode", "", "" },
  { 0, 3, HEX, "HEX", "Hexadecimal mode", "", "" },
  { 0, 4, ASCIIM, "ASC", "Ascii mode", "", "" },
  { 0, 5, IP, "IP", "IP address mode", "", "" },
  { 0, 6, NOP, " ", " ", "", "" },
  { 0, 7, NOP, " ", " ", "", "" },
  { 1, 0, dAND, "AND", "x and y", " AND ", "" },
  { 1, 1, dOR, "OR", "y or x", " OR ", "" },
  { 1, 2, dXOR, "XOR", "y xor x", " XOR ", "" },
  { 1, 3, MODULUS, "MOD", "y mod x", " MOD ", "" },
  { 1, 4, dNOT, "~X", "not X (complement)", "NOT ", "" },
  { 1, 5, SHIFTYL, "y<<x", "Shift Y, X bits left", "<<", ">>" },
  { 1, 6, SHIFTYR, "y>>x", "Shift Y, X bits right", ">>", "<<" },
  { 1, 7, NOP, " ", " ", "", "" },
  { 2, 0, INV, "INV", "Invert functions", "", "" },
  { 2, 1, PRIMEF, "PF", "Prime factors of X", "PF(", "" },
  { 2, 2, NOP, " ", " ", "", "" },
  { 2, 3, NOP, " ", " ", "", "" },
  { 2, 4, NOP, " ", " ", "", "" },
  { 2, 5, SHIFTL, "<<", "Shift X left 1 bit", "<<1 ", ">>1 " },
  { 2, 6, SHIFTR, ">>", "Shift X right 1 bit", ">>1 ", "<<1 " },
  { 2, 7, EVAL, "Eval", "Last algebraic expression", "", "" },
  { -1, -1, 0, " ", " ", "", "" }
};

dcalc_button float_buttons[] = {
  { 0, 0, FIN, "FIN", "Finance mode", "", "" },
  { 0, 1, STAT, "STA", "Statistics mode", "", "" },
  { 0, 2, PROG, "PRO", "Programmers mode", "", "" },
  { 0, 3, NOP, " ", " ", "", "" },
  { 0, 4, 'E', "E", " ", "E", "" },
  { 0, 5, PERCENT, "%", "X percent of Y (or INV)", "%", "" },
  { 1, 0, YTOX, "y^X", "Y to the power of X", "^", "" },
  { 1, 1, SQR, "x2", "X squared", "^2 ", "" },
  { 1, 2, ROOT, "SQRT", "Square root of X", "SQRT(", "" },
  { 1, 3, NOP, " ", " ", "", "" },
  { 1, 4, RECI, "1/X", "Reciprocal of X", " 1/", "" },
  { 1, 5, PERCENTCH, "%CH", "Percentage change from Y to X (or INV)", "%ch ", "" },
  { 2, 0, FIX, "FIX", "Floating point notation", "", "" },
  { 2, 1, SCIFORMAT, "SCI", "Scientific notation", "", "" },
  { 2, 2, ENG, "ENG", "Engineering notation", "", "" },
  { 2, 3, '7', "7", " ", "7", "" },
  { 2, 4, '8', "8", " ", "8", "" },
  { 2, 5, '9', "9", " ", "9", "" },
  { 3, 0, STORE, "STO", "Store X to a register", "", "" },
  { 3, 1, STOPLUS, "ST+", "Add X to a register", "", "" },
  { 3, 2, STOMINUS, "ST-", "Subtract X from a register", "", "" },
  { 3, 3, '4', "4", " ", "4", "" },
  { 3, 4, '5', "5", " ", "5", "" },
  { 3, 5, '6', "6", " ", "6", "" },
  { 4, 0, RECALL, "RCL", "Recall from a register", "", "" },
  { 4, 1, CLR, "CLs", "Clear stack (INV= clear registers)", "", "" },
  { 4, 2, NOP, " ", " ", "", "" }, /* reserved for CLu */
  { 4, 3, '1', "1", " ", "1", "" },
  { 4, 4, '2', "2", " ", "2", "" },
  { 4, 5, '3', "3", " ", "3", "" },
  { 5, 0, ROLLDOWN, "ROLL", "Roll stack down", "", "" },
  { 5, 1, CLX, "CLx", "Clear X", "", "" },
  { 5, 2, BACKSPACE, "BSP", "Backspace", "", "" },
  { 5, 3, '0', "0", " ", "0", "" },
  { 5, 4, '.', ".", " ", ".", "" },
  { 5, 5, CHS, "CHS", "Change sign of X", "-", "" },
  { -1, -1, 0, " ", " ", "", "" }
};

dcalc_button int_buttons[] = {
  { 0, 0, SCI, "SCI", "Scientific mode", "", "" },
  { 0, 1, FIN, "FIN", "Finance mode", "", "" },
  { 0, 2, STAT, "STA", "Statistics mode", "", "" },
  { 0, 3, 'D', "D", " ", "D", "" },
  { 0, 4, 'E', "E", " ", "E", "" },
  { 0, 5, 'F', "F", " ", "F", "" },
  { 1, 0, YTOX, "y^X", "Y to the power of X", "^", "" },
  { 1, 1, SQR, "x2", "X squared", "^2 ", "" },
  { 1, 2, NOP, " ", " ", "", "" },
  { 1, 3, 'A', "A", " ", "A", "" },
  { 1, 4, 'B', "B", " ", "B", "" },
  { 1, 5, 'C', "C", " ", "C", "" },
  { 2, 0, NOP, " ", " ", "", "" },
  { 2, 1, NOP, " ", " ", "", "" },
  { 2, 2, NOP, " ", " ", "", "" },
  { 2, 3, '7', "7", " ", "7", "" },
  { 2, 4, '8', "8", " ", "8", "" },
  { 2, 5, '9', "9", " ", "9", "" },
  { 3, 0, STORE, "STO", "Store X to a register", "", "" },
  { 3, 1, STOPLUS, "ST+", "Add X to a register", "", "" },
  { 3, 2, STOMINUS, "ST-", "Subtract X from a register", "", "" },
  { 3, 3, '4', "4", " ", "4", "" },
  { 3, 4, '5', "5", " ", "5", "" },
  { 3, 5, '6', "6", " ", "6", "" },
  { 4, 0, RECALL, "RCL", "Recall from a register", "", "" },
  { 4, 1, CLR, "CLs", "Clear stack (INV= clear registers)", "", "" },
  { 4, 2, NOP, " ", " ", "", "" },
  { 4, 3, '1', "1", " ", "1", "" },
  { 4, 4, '2', "2", " ", "2", "" },
  { 4, 5, '3', "3", " ", "3", "" },
  { 5, 0, ROLLDOWN, "ROLL", "Roll stack down", "", "" },
  { 5, 1, CLX, "CLx", "Clear X", "", "" },
  { 5, 2, BACKSPACE, "BSP", "Backspace", "", "" },
  { 5, 3, '0', "0", " ", "0", "" },
  { 5, 4, '.', ".", " ", ".", "" },
  { 5, 5, CHS, "CHS", "Change sign of X", "", "" },
  { -1, -1, 0, " ", " ", "", "" }
};

void
set_x(char *inbuf) {
	insertedTextIsFromDcalc = 1;
	gtk_entry_set_text(entryX, inbuf);
	insertedTextIsFromDcalc = 0;
}

void
append_x(char *inbuf) {
	insertedTextIsFromDcalc = 1;
	gtk_entry_append_text(entryX, inbuf);
	insertedTextIsFromDcalc = 0;
}

const char const *get_x() {
	return(gtk_entry_get_text(entryX));
}

static int
prepareKey(dcalc_button *b) {
	if (!algebraic_mode)
		return(b->command); /* RPN is too easy! */

	switch (b->command) {
		/* These needY: */
	case COMB:
	case DIVIDE12:
	case DIVIDE:
	case DYS:
	case SHIFTL:
	case SHIFTR:
	case SHIFTYL:
	case SHIFTYR:
	case MINUS:
	case MULT:
	case PERM:
	case PLUS:
	case RTOP:
	case SQR:
	case TIMES12:
	case YTOX:
	case dAND:
	case dOR:
	case dXOR:
		last_was_fin_key = 0;
		if (liftStack()) {
			set_x("ans ");
		}
		if (isInverted())
			append_x(b->invtext);
		else
			append_x(b->text);
		return(NOP);

	case PERCENT:
		last_was_fin_key = 0;
		append_x("%");
		on_Equals_clicked(NULL, NULL);
		return(NOP);

	case EVAL:
		last_was_fin_key = 0;
		liftStack();
		set_x(last_eval);
		return(NOP);

	case BACKSPACE:
	{
		char buf[200];
		int len;
		isInverted();
		last_was_fin_key = 0;
		if (lift_needed) {
			set_x("");
			return(BACKSPACE);
		}
		strcpy(buf, get_x());
		len = strlen(buf);
		if (len) {
			buf[len - 1] = 0;
			set_x(buf);
		}
	}
	return(NOP);

	case CLR:
		process(b->command);
		set_x("");
		return(NOP);

	case CLX:
		set_x("");
		lift_needed = 0;
		last_was_fin_key = 0;
		return(NOP);

	case 'F':
	case 'f':
	case 'E':
	case 'e':
	case 'D':
	case 'd':
	case 'C':
	case 'c':
	case 'B':
	case 'b':
	case 'A':
	case 'a':
		if ((mode == PROG && intmode == HEX) ||
			(mode != PROG && toupper(b->command) == 'E'))
			/* is OK */;
		else
			return(NOP);
	case '9':
	case '8':
		if (mode == PROG && ((intmode == BIN) || (intmode == OCT)))
			return(NOP);
	case '7':
	case '6':
	case '5':
	case '4':
	case '3':
	case '2':
		if (mode == PROG && intmode == BIN)
			return(NOP);
	case '1':
	case '0':
	case '.':
		if ((b->command == '.') && (mode == PROG) && (intmode != IP))
			return(NOP);
		last_was_fin_key = 0;
		if (liftStack()) {
			set_x("");
		}
		if (isInverted() && strlen(b->invtext))
			append_x(b->invtext);
		else
			append_x(b->text);
		return(NOP);

	case INV:
		return(b->command);

	case RECALL:
		if (liftStack()) {
			set_x("");
		}
		exec_recall();
		return NOP;

	default:
		if (liftStack()) {
			set_x("");
		}

		if (strlen(b->text)) {
			last_was_fin_key = 0;
			if (isInverted() && strlen(b->invtext))
				append_x(b->invtext);
			else
				append_x(b->text);
		} else { /* just do the command or key: */
			int saveInv = invert;
			strcpy(last_eval, get_x());
			if (mode == PROG)
				pop();
			else
				popf();;
			exec_equals();
			invert = saveInv;
			return(b->command);
		}
		return(NOP);
	}
	return(NOP);
}

int 
button_command(dcalc_button *b, int i, int j) {
	while (b != NULL && b->i >= 0)
		if (b->i == i && b->j == j)
			return(prepareKey(b));
		else
			b++;
	return(NOP);
}

static void display_panel(char which_panel, dcalc_button *b) {
	gpointer g;
	char widget_name[80];

	if (which_panel == 'R')
		r_buttons = b;
	else
		l_buttons = b;

	while (b != NULL && b->i >= 0) {
		sprintf(widget_name, "%c%d_%d", which_panel, b->i, b->j);
		g = gtk_object_get_data(GTK_OBJECT (main_window), widget_name);
		if (g) {
			GtkWidget *child;
			GtkTooltipsData *tooltipsdata;

			child = GTK_BIN (g)->child;
			if (GTK_IS_LABEL (child)) {
				gtk_label_set_text (GTK_LABEL (child), b->label);
			}
			tooltipsdata = gtk_tooltips_data_get(g);
			if (tooltipsdata) {
                if (b->tooltip[0] == 0) {
                    gtk_tooltips_disable(tooltipsdata->tooltips);
                } else {
                    gtk_tooltips_enable(tooltipsdata->tooltips);
                    gtk_tooltips_set_tip(tooltipsdata->tooltips, g, b->tooltip, NULL);
                }
			} else
				fprintf(stderr, "gdcalc: Can't find tooltip for widget %s\n", widget_name);
		} else
			fprintf(stderr, "gdcalc: Can't find widget %s\n", widget_name);
		b++;
	}
}

void display_buttons(int c) {
	GtkWidget *w;

	if (c == PROG) {
		display_panel('R', int_buttons);
		display_panel('L', prog_buttons);
	} else {
		switch (c) {
		case STAT:
			float_buttons[0].command = PROG;
			strcpy(float_buttons[0].label, "PRO");
			strcpy(float_buttons[0].tooltip, "Programmers mode");
			float_buttons[1].command = SCI;
			strcpy(float_buttons[1].label, "SCI");
			strcpy(float_buttons[1].tooltip, "Scientific mode");
			float_buttons[2].command = FIN;
			strcpy(float_buttons[2].label, "FIN");
			strcpy(float_buttons[2].tooltip, "Finance mode");
			display_panel('L', stat_buttons);	
			break;
		case FIN:
			float_buttons[0].command = STAT;
			strcpy(float_buttons[0].label, "STA");
			strcpy(float_buttons[0].tooltip, "Statistics mode");
			float_buttons[1].command = PROG;
			strcpy(float_buttons[1].label, "PRO");
			strcpy(float_buttons[1].tooltip, "Programmers mode");
			float_buttons[2].command = SCI;
			strcpy(float_buttons[2].label, "SCI");
			strcpy(float_buttons[2].tooltip, "Scientific mode");
			display_panel('L', fin_buttons);
			break;
		default: /* SCI */
			float_buttons[0].command = FIN;
			strcpy(float_buttons[0].label, "FIN");
			strcpy(float_buttons[0].tooltip, "Finance mode");
			float_buttons[1].command = STAT;
			strcpy(float_buttons[1].label, "STA");
			strcpy(float_buttons[1].tooltip, "Statistics mode");
			float_buttons[2].command = PROG;
			strcpy(float_buttons[2].label, "PRO");
			strcpy(float_buttons[2].tooltip, "Programmers mode");
			display_panel('L', sci_buttons);
			break;
		}
		display_panel('R', float_buttons);
	}      
	w = gtk_object_get_data(GTK_OBJECT(main_window), "degree");
	if (w)
		gtk_widget_set_sensitive(w, (c==PROG)? 0: 1);
	else
		fprintf(stderr, "gdcalc: can't find degree menu item\n");

	w = gtk_object_get_data(GTK_OBJECT(main_window), "radians");
	if (w)
		gtk_widget_set_sensitive(w, (c==PROG)? 0: 1);
	else
		fprintf(stderr, "gdcalc: can't find radians menu item\n");

	w = gtk_object_get_data(GTK_OBJECT(main_window), "annuity_in_advance");
	if (w)
		gtk_widget_set_sensitive(w, (c==FIN)? 1: 0);
	else
		fprintf(stderr, "gdcalc: can't find annuity menu item\n");

	w = gtk_object_get_data(GTK_OBJECT(main_window), "convert");
	if (w)
		gtk_widget_set_sensitive(w, (c==PROG)? 0: 1);
	else
		fprintf(stderr, "gdcalc: can't find convert menu item\n");

	w = gtk_object_get_data(GTK_OBJECT(main_window), "fixed_point_numbering");
	if (w)
		gtk_widget_set_sensitive(w, (c==PROG)? 0: 1);
	else
		fprintf(stderr, "gdcalc: can't find fixed_point_mode menu item\n");

	w = gtk_object_get_data(GTK_OBJECT(main_window), "engineering_numbering");
	if (w)
		gtk_widget_set_sensitive(w, (c==PROG)? 0: 1);
	else
		fprintf(stderr, "gdcalc: can't find engineering_mode menu item\n");

	w = gtk_object_get_data(GTK_OBJECT(main_window), "scientific_numbering");
	if (w)
		gtk_widget_set_sensitive(w, (c==PROG)? 0: 1);
	else
		fprintf(stderr, "gdcalc: can't find scientific_numberingmenu item\n");

	w = gtk_object_get_data(GTK_OBJECT(main_window), "places");
	if (w)
		gtk_widget_set_sensitive(w, (c==PROG)? 0: 1);
	else
		fprintf(stderr, "gdcalc: can't find places menu item\n");

#ifdef HAS_ALGEBRAIC_MODE
    if (algebraic_mode) {
        on_algebraic_activate(NULL, NULL);
    } else {
        on_rpn_activate(NULL, NULL);
    }
#endif
}

static void print_number(char *buf, char *name) 
{
	gpointer g;
	g = gtk_object_get_data(GTK_OBJECT (main_window), name);

	gtk_entry_set_text (GTK_ENTRY (g), buf);
}

void print_x(char *buf) {
	set_x(buf);
}

void
add_x(char *buf) {
	append_x(buf);
}

void dispnums()
{
    char 	outbuf[80];

    if (entering) {
		strcpy(outbuf, inbuf);
    } else
		fmt_base(outbuf, xiReg, xfReg);

    prep_for_output(outbuf);
    print_x(outbuf);
    
    fmt_base(outbuf, yiReg, yfReg);
    prep_for_output(outbuf);
    print_number(outbuf, "entry_Y");

    fmt_base(outbuf, ziReg, zfReg);
    prep_for_output(outbuf);
    print_number(outbuf, "entry_Z");

    fmt_base(outbuf, tiReg, tfReg);
    prep_for_output(outbuf);
    print_number(outbuf, "entry_T");

    fmt_base(outbuf, liReg, lfReg);
    prep_for_output(outbuf);
    print_number(outbuf, "entry_L");
}

/* only used for the bell ... */
void put_a_char(int i) {
	gdk_beep();
}

static char *printBase() {
	if (mode == PROG)
		switch (intmode) {
		case ASCIIM:
			return("prog:asc: ");
		case BIN:
			return("prog:bin: ");
		case OCT:
			return("prog:oct: ");
		case DEC:
			return("prog:dec: ");
		case HEX:
			return("prog:hex: ");
		} 
	else
		if (l_buttons == sci_buttons)
			return "sci: ";
		else if (l_buttons == fin_buttons)
			return "fin: ";
		else
			return "stats: ";
	return "";
}

static char *printInv() {
    if (invert)
		return("inv: ");
    else
		return("");
}

static char *printDeg(){
    if (degree)
		return("deg: ");
    else
		return("rad: ");
}

void msg(char *buf) {
	gint context_id;
	gpointer status_bar;
	char status[200];

	strcpy(status, printBase());
	if (mode != PROG) {
		strcat(status, printDeg());
	}
	strcat(status, printInv());
	strcat(status, " ");
	strcat(status, buf);
	status_bar = gtk_object_get_data(GTK_OBJECT (main_window), _("statusbar"));
	context_id = gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar), 
											  "Statusbar example");
	gtk_statusbar_push( GTK_STATUSBAR(status_bar), context_id, status);
}

void clear_msg() {
	msg("");
}

void print_inv() {
	gtk_button_set_relief(invert_button, invert? GTK_RELIEF_NONE: GTK_RELIEF_NORMAL);
}

/* These not needed for GTK version: */
void prinbase() {};
void print_string(char *buf) {}
void print_deg(){}
void pop_up_help(void) {}
void os_raw_mode(int i) { raw_mode = 0 /* i */; }
void os_init(void) {}
void os_term(void) {gtk_main_quit();}
int get_a_char(int *c) {return 0;}

int dialog(char *buf) {
	GtkWidget *dialog_popup;
	gpointer g;
	int reply;

	dialog_popup = create_gen_dialog ();
	g = gtk_object_get_data(GTK_OBJECT (dialog_popup), _("msg"));
	gtk_label_set_text(GTK_LABEL(g), buf);
	reply = gtk_dialog_run(GTK_DIALOG(dialog_popup));
	gtk_widget_destroy(dialog_popup);
	return (reply==0)? 'Y': 'N';
}

int places(char *buf) {
	GtkWidget *places_dialog;
	GtkSpinButton *spinbutton;
	int reply;
	gfloat decplacesf = decplaces;

	places_dialog = create_places ();
	spinbutton = gtk_object_get_data(GTK_OBJECT (places_dialog), _("places_spinbutton"));
	gtk_spin_button_set_value(spinbutton, decplacesf);

	reply = gtk_dialog_run(GTK_DIALOG(places_dialog));
	if (reply == 0)
		reply = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinbutton));
	else
		reply = -1;

	gtk_widget_destroy(places_dialog);

	return reply;
}

int eval(char *buf, char *expr) {
	GtkEntry *eval_expr_entry;
	int reply;

	eval_dialog = create_eval ();
	eval_expr_entry = gtk_object_get_data(GTK_OBJECT (eval_dialog), _("eval_expr"));
	gtk_entry_set_text( eval_expr_entry, buf);
	reply = gtk_dialog_run(GTK_DIALOG(eval_dialog));
	if (reply == 0) {
		strcpy(expr, gtk_entry_get_text(eval_expr_entry));
	} else
		reply = -1;

	gtk_widget_destroy(eval_dialog);

	return reply;
}

static void
setFont(char *widgetName, GtkWidget *main_window, GdkFont *newFont) {
	GtkWidget *widget;
	GtkStyle *style;

	widget = gtk_object_get_data(GTK_OBJECT (main_window), widgetName);
	if (!widget) {
		fprintf(stderr, "gdcalc: setFont: can't find %s\n", widgetName);
		return;
	}
	style = gtk_widget_get_style(widget);
	if (!style) {
		fprintf(stderr, "gdcalc: setFont: can't find for widget %s\n", widgetName);
		return;
	}
	gdk_font_unref (style->private_font);
	style->private_font = newFont;
	gdk_font_ref (style->private_font);
	gtk_widget_set_style (widget, style);
}

void 
setPlusMinusFont(char *fontName) {
	GdkFont *newFont;

	newFont = gdk_font_load(fontName);
	if (!newFont) {
		fprintf(stderr, "gdcalc: can't find font \"%s\"\n", fontName);
		return;
	}
	setFont("Equals", main_window, newFont);
	setFont("LeftBrace", main_window, newFont);
	setFont("RightBrace", main_window, newFont);
	setFont("Plus", main_window, newFont);
	setFont("Minus", main_window, newFont);
	setFont("Mult", main_window, newFont);
	setFont("Divide", main_window, newFont);
}

void 
setButtonFont(char *fontName) {
	GdkFont *newFont;
	int row, col;
	char widgetName[100];

	newFont = gdk_font_load(fontName);
	if (!newFont) {
		fprintf(stderr, "gdcalc: can't find font \"%s\"\n", fontName);
		return;
	}

	for (row = 0; row < 3; row++)
		for (col = 0; col < 8; col++) {
			sprintf(widgetName, "L%d_%d", row, col);
			setFont(widgetName, main_window, newFont);
		}
	for (row = 0; row < 6; row++)
		for (col = 0; col < 6; col++) {
			sprintf(widgetName, "R%d_%d", row, col);
			setFont(widgetName, main_window, newFont);
		}
	setFont("Enter", main_window, newFont);
}

#ifdef RUNTIME_FONT_CHANGES_ARE_WORKING
void 
fixFont(char *newFont, GtkWidget *this_main_window, char *name) {
	GdkFont *fixed_font;

	fixed_font = gdk_font_load(newFont);
	if (!fixed_font) {
		fprintf(stderr, "gdcalc: fixFont: can't find font \"%s\"\n", newFont);
		return;
	}
	setFont(name, this_main_window, fixed_font);
}
#endif

static void xdispreg(GtkWidget *dialog, int i) {
	char labelname[80], outbuf[80];
	GtkWidget *entry;

	if (dialog) {
		sprintf(labelname, "mem%d", i);
#ifdef RUNTIME_FONT_CHANGES_ARE_WORKING
		fixFont(calculatorFont, dialog, labelname);
#endif
		entry = gtk_object_get_data(GTK_OBJECT (dialog), labelname);
		fmt_base(outbuf, reg[i], regf[i]);
		prep_for_output(outbuf);
		if (l_buttons == fin_buttons)
			switch (i) {
			case FIN_NUM_REG: strcat(outbuf, " = periods"); break;
			case FIN_INT_REG: strcat(outbuf, " = interest (%)"); break;
			case FIN_PVAL_REG: strcat(outbuf, " = PVal"); break;
			case FIN_PMT_REG: strcat(outbuf, " = payment"); break;
			case FIN_FVAL_REG: strcat(outbuf, " = FVal"); break;
			}
		else if (l_buttons == stat_buttons)
			switch (i) {
			case STAT_R2: strcat(outbuf, " = correlation (1=good 0=poor)"); break;
			case STAT_Y_INT: strcat(outbuf, " = Y intersect"); break;
			case STAT_SLOPE: strcat(outbuf, " = slope"); break;
			case STAT_NUM_REG: strcat(outbuf, " = n"); break;
			case STAT_SUMX_REG: strcat(outbuf, " = sum of X's"); break;
			case STAT_SUMX2_REG: strcat(outbuf, " = sum of x2's"); break;
			case STAT_SUMY_REG: strcat(outbuf, " = sum of Y's"); break;
			case STAT_SUMY2_REG: strcat(outbuf, " = sum of y2's"); break;
			case STAT_SUMXY_REG: strcat(outbuf, " = sum of XY's"); break;
			}

		gtk_entry_set_text(GTK_ENTRY(entry), outbuf);
	}
}

void dispreg(int i) {
	xdispreg(registers, i);
}

void dispregs(void) {
	int i;

	if (registers)
		for (i = 0; i < NUMREGS; i++)
			dispreg(i);
}

void toggle_registers(void) {
	if (!registers) {
		registers = create_mem_dialog();
		dispregs();
		gtk_widget_show(registers);
	} else {
		gtk_widget_destroy(registers);
		registers = NULL;
	}
}

void pop_up_reg(void) {
	toggle_registers();
}

static int do_mem_dialog(char *buf) {
	int reply, i;

	mem_dialog = create_mem_dialog ();
	gtk_window_set_title (GTK_WINDOW (mem_dialog), buf);
	for (i=0; i < NUMREGS; i++)
		xdispreg(mem_dialog, i);
	reply = gtk_dialog_run(GTK_DIALOG(mem_dialog));
	gtk_widget_destroy(mem_dialog);
	return (reply==0)? -1: mem_value+'0';
}

int store(char *buf) {
	return(do_mem_dialog("Store..."));
}

int recall(char *buf) {
	return(do_mem_dialog("Recall..."));
}

void on_algebraic_activate();

static void
setName(char *widgetName, char *name) {
	GtkWidget *w;

	w =  (GtkWidget *) gtk_object_get_data(GTK_OBJECT (main_window), widgetName);
	if (!w) {
		fprintf(stderr, "gdcalc: Can't find widget %s\n", widgetName);
		return;
	}
	gtk_widget_set_name(w, name);
}

int
main(int argc, char *argv[])
{
	char *cfont = NULL, *bfont = NULL, *pfont = NULL;
	char rcFileName[MAXPATHLEN];
	struct poptOption options[] = {
		{"calculatorFont", 'f', POPT_ARG_STRING, NULL, 0, "Font for numbers", "FONT"},
		{"buttonFont", 'b', POPT_ARG_STRING, NULL, 0, "Font for buttons", "FONT"},
		{"plusMinusFont", 'p', POPT_ARG_STRING, NULL, 0, "Font for +, - etc", "FONT"},
		{NULL, '\0', 0, NULL, 0, NULL, NULL} /* end the list */
	};
	GtkWidget *w;

/* apparently not needed:
	bindtextdomain (PACKAGE, PACKAGE_LOCALE_DIR);
	textdomain (PACKAGE);
*/

	options[0].arg = &cfont;
	options[0].arg = &bfont;
	options[0].arg = &pfont;
	gnome_init_with_popt_table("gdcalc", VERSION, argc, argv, options, 0, NULL);

	if (cfont && *cfont)
		strcpy(calculatorFont, cfont);
	else
		strcpy(calculatorFont, "-misc-fixed-medium-r-*-*-14-*-*-*-*-*-*-*");  

	if (bfont && *bfont)
		strcpy(buttonFont, bfont);
	else
		strcpy(buttonFont, "-misc-fixed-medium-r-*-*-14-*-*-*-*-*-*-*");  

	if (pfont && *pfont)
		strcpy(plusMinusFont, pfont);
	else
		strcpy(plusMinusFont, "-misc-fixed-medium-r-*-*-14-*-*-*-*-*-*-*");  

	main_window = create_main_window ();

	/* Assign names that can be picked up by resource file: */
	setName("Plus", "big_button");
	setName("Minus", "big_button");
	setName("Mult", "big_button");
	setName("Divide", "big_button");
	setName("LeftBrace", "big_button");
	setName("RightBrace", "big_button");
	setName("Equals", "big_button");
	/* setName("R5_4", "big_button"); .. decimal - distorts the display too much */

	strcpy(rcFileName, getenv("HOME"));
	strcat(rcFileName, "/.gdcalc.rc");
	gtk_rc_parse(rcFileName);

#ifdef RUNTIME_FONT_CHANGES_ARE_WORKING
	/* Load a fixed font for the numeric displays: */
	fixFont(calculatorFont, main_window, "entry_X");
	fixFont(calculatorFont, main_window, "entry_Y");
	fixFont(calculatorFont, main_window, "entry_Z");
	fixFont(calculatorFont, main_window, "entry_T");
	fixFont(calculatorFont, main_window, "entry_L");
  
	setButtonFont(buttonFont);
	setPlusMinusFont(plusMinusFont);
#endif

	gtk_widget_draw(main_window, NULL);
	gtk_widget_show (main_window);

	entryX = (GtkEntry *) gtk_object_get_data(GTK_OBJECT (main_window), "entry_X");
	if (!entryX) {
		fprintf(stderr, "gdcalc: Can't find widget entry_X\n");
		exit(1);
	}

	invert_button = (GtkButton *) gtk_object_get_data(GTK_OBJECT (main_window), "L2_0");
	if (!invert_button) {
		fprintf(stderr, "gdcalc: Can't find widget for invert button\n");
		exit(1);
	}
		
	initialise();
	display_buttons(mode);

	/* gtk_check_menu_item_set_active actually calls the widgets activate method - ie 
	   simulating a button release!! This can lead to an infinite loop of invocations */
	w = gtk_object_get_data(GTK_OBJECT(main_window), 
							(mode==SCI)? "scientific_mode":
							(mode==FIN)? "financial_mode":
							(mode==STAT)? "statistics_mode":
							"programming_mode");
	if (w)
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), 1);
	else
		fprintf(stderr, "gdcalc: Can't find main mode item in menu\n");

	w = gtk_object_get_data(GTK_OBJECT(main_window), degree? "degree": "radians");
	if (w)
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), 1);
	else
		fprintf(stderr, "gdcalc: Can't find degree/radians item in menu\n");

	w = gtk_object_get_data(GTK_OBJECT(main_window), 
							(floatmode==ENG)? "engineering_numbering":
							(floatmode==SCI)?"scientific_numbering":
							"fixed_point_numbering");
	if (w)
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), 1);
	else
		fprintf(stderr, "gdcalc: Can't find floating point item in menu\n");

	w = gtk_object_get_data(GTK_OBJECT(main_window), "annuity_in_advance");
	if (w)
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), finPayAt0? 1: 0);
	else
		fprintf(stderr, "gdcalc: Can't find annuity item in menu\n");

	w = gtk_object_get_data(GTK_OBJECT(main_window), algebraic_mode?"algebraic":"rpn");
	if (w)
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), 1);
	else
		fprintf(stderr, "gdcalc: Can't find algebraic/rpn item in menu\n");

#ifndef RUNTIME_FONT_CHANGES_ARE_WORKING
	w = gtk_object_get_data(GTK_OBJECT(main_window), "font");
	if (w)
		gtk_widget_hide(w);
	else
		fprintf(stderr, "gdcalc: Can't find font item in menu\n");
	w = gtk_object_get_data(GTK_OBJECT(main_window), "button_font");
	if (w)
		gtk_widget_hide(w);
	else
		fprintf(stderr, "gdcalc: Can't find button_font item in menu\n");
	w = gtk_object_get_data(GTK_OBJECT(main_window), "plus_minus_font");
	if (w)
		gtk_widget_hide(w);
	else
		fprintf(stderr, "gdcalc: Can't find plus_minus_font item in menu\n");
#endif

	dispnums();
	msg(DEF_SIG(VERSION));

	if (registers) { /* set to 1 by readGuiSettings */
		registers = NULL;
		toggle_registers();
	}

	gtk_main ();
	return 0;
}


/* For emacs: */

/* Local Variables: */
/* eval:(setq tab-width 4) */
/* End: */
